# coding:utf-8
from flask import current_app, jsonify

from app.libs.redprint import Redprint
from app.libs.error_code import ClientTypeError, Success, AuthFailed
from app.models.user import User
from app.validators.forms import ClientForm, UserEmailForm, TokenForm
from app.libs.enums import ClientTypeEnum
from itsdangerous import Serializer, SignatureExpired, BadSignature
import jwt
import time

api = Redprint('client')


@api.route('/register', methods=['POST'])
def register():
    form = ClientForm().validate_for_api()
    promise = {
        ClientTypeEnum.USER_EMAIL: __register_user_by_email
    }
    promise[form.type.data]()

    return Success()


def __register_user_by_email():
    form = UserEmailForm().validate_for_api()
    User.register_by_email(form.nickname.data, form.account.data, form.secret.data)
    pass


@api.route('/login', methods=['POST'])
def login():
    form = ClientForm().validate_for_api()
    promise = {
        ClientTypeEnum.USER_EMAIL: User.verify
    }
    identity = promise[ClientTypeEnum(form.type.data)](
        form.account.data,
        form.secret.data
    )
    # Token
    # 过期时间
    expiration = current_app.config['TOKEN_EXPIRATION']
    token = generate_auth_token(identity['uid'],
                                form.type.data,
                                identity['scope'],
                                expiration)
    res = {
        'code': 0,
        'message': 'success',
        'data': token
    }
    return jsonify(res), 200


@api.route('/secret', methods=['POST'])
def get_token_info():
    """获取令牌信息"""
    form = TokenForm().validate_for_api()
    s = Serializer(current_app.config['SECRET_KEY'])
    try:
        data = s.loads(form.token.data, return_header=True)
    except SignatureExpired:
        raise AuthFailed(message='token is expired', error_code=1003)
    except BadSignature:
        raise AuthFailed(message='token is invalid', error_code=1002)

    r = {
        'scope': data[0]['scope'],
        'create_at': data[1]['iat'],
        'expire_in': data[1]['exp'],
        'uid': data[0]['uid']
    }
    return jsonify(r)


def generate_auth_token(uid, ac_type, scope=None, expiration=7200):
    """生成令牌 expires_in=expiration"""
    # payload 为一个字典，token的第二部分，存储用户名、id等等，不要存储敏感数据
    # 'expiration'是一个默认可以设置过期失效，用现在的时间戳，加上要让token存在多长时间
    payload = {
        'uid': uid,
        'type': ac_type.value,
        'scope': scope,
        'expiration': time.time() + expiration
    }
    # key 是一个随机码，相当于给加密加盐，是加密数据更加不容易被破解
    key = current_app.config['SECRET_KEY']
    token = jwt.encode(payload, key=key, algorithm='HS256')
    return token
